import { useState } from 'react'
import { useEffect, lazy, Fragment, useRef } from 'react'
/* -------------------------------------------------------- Declare -- */
const { $lazy, $fn, $, $config } = window
import Rules from './rules'
/* -------------------------------------------------------- Async Component -- */
const FormItem = lazy(()=>import('@antd/form/layout/item'))
const Input = lazy(()=>import('@antd/form/input'))
const InputRange = lazy(()=>import('@antd/form/input-range'))
const Select = lazy(()=>import('@antd/form/select'))
const Checkbox = lazy(()=>import('@antd/form/checkbox'))
const CheckboxGroup = lazy(()=>import('@antd/form/checkbox-group'))
const Switch = lazy(()=>import('@antd/form/switch'))
const Radio = lazy(()=>import('@antd/form/radio'))
const Transfer = lazy(()=>import('@antd/form/transfer'))
const DatePicker = lazy(()=>import('@antd/form/date-picker'))
const TimePicker = lazy(()=>import('@antd/form/time-picker'))
const DatePickerRange = lazy(()=>import('@antd/form/date-picker/range'))
const Upload = lazy(()=>import('@antd/form/upload'))
const TreeSelect = lazy(()=>import('@antd/form/tree-select'))
const Tree = lazy(()=>import('@antd/form/tree'))
const Cascader = lazy(()=>import('@antd/form/cascader'))
const Title = $lazy.load(()=>import('#tp/title/title'))
// 自定义
const Table = $lazy.hook(()=>import('@antd/table'))
const SelectContent = lazy(()=>import('#cpt/form-element/select-content'))
const TableEdit = lazy(()=>import('#cpt/form-element/table-edit'))
let clear
/* -------------------------------------------------------- 按钮组配置 -- */
const Index = ({
	className, 			/** @param {Boolean}			# 盒子 className */
	style, 				/** @param {Boolean}			# 盒子 style */
	data, 				/** @param {String}				# 列表数据 */
	mb=20, 				/** @param {Number}				# 间距 */
	disabled, 			/** @param {Boolean}			# 禁用 */
	readOnly, 			/** @param {Boolean}			# 只读 */
	colon,				/** @param {Boolean}			# 是否有冒号 */
	size='small',		/** @param {String}				# 元素大小 */
	paddingClass, 		/** @param {String}				# 内容补白 */
	// onChanged, 			/** @param {Event}			# 元素改变时执行 */
	// onSubmit, 			/** @param {Function}			# 提交表单执行 */
	onInit, 			/** @param {Event}				# 初始化 */
	x, 					/** @param {Boolean}			# 是否横向 */
	width,				/** @param {Number}				# 全部默认宽度 */
	labelWidth,			/** @param {Number}				# 标签宽度 */
	cache=$config.cache,/** @param {Boolan}				# 是否缓存 */
	form, 				/** @param {Object}				# 存储值 */
	submit, 			/** @param {Object}				# 额外值 */
	formRef, 			/** @param {Object}				# formRef */
	expose, 			/** @param {Object}				# 暴露方法 */
	listData,			/** @param {Object}				# 回显数据 */
	infoData,
	ctrlMode,			/** @param {Object}				# 模式 */
	nowrap, 			/** @param {Boolean}			# 是否换行排列 */
	group, 				/** @param {Boolean}			# 是否分组 */
	// search
	gapX=8, 			/** @param {Component}			# 横向间距 */
	gapY=5,				/** @param {Component}			# 纵向间距 */
	isSearch 			/** @param {Boolean}			# 是否是搜索表单 */
}) => {
	const cascaderRef = useRef()
	const exposeRef = useRef()
	let gapStyle = x ? { gap:`${gapY}px ${gapX}px` } : null
	const [ model, setModel ] = useState(data)
	useEffect(()=>{
		if(onInit){
			clear = setTimeout(onInit ,200)
			return () => clearTimeout(clear)
		}
	},[])  // eslint-disable-line
	
	useEffect(()=>{
		if( group && $fn.hasArray(data)){
			let stack = [ ]
			data.forEach( v => {
				if($fn.hasArray(v.children) && !v.hide) {
					stack = [ ...stack, { title:v.title }, ...v.children]
				}else{
					stack.push(v)
				}
			} )
			setModel( stack )
		}
	},[data]) // eslint-disable-line
	// return null
	return (
		<div className={` ${nowrap ? 'fx' : 'fxw'} ${$.css(paddingClass)} ${$.css(className)}`} style={{...gapStyle, ...style}}>
			{
				$fn.hasArray( model ) && model.map((v,i)=>{
					if( !$fn.hasObject(v) ) return
					let { 
						label, _label, type, hide, name, ml, el, param, domRef, suffix, antd, p,
						sname, api, nameStr, idStr, table, click, mode, height, setName, data, change, mul,
						format, mongo, names, cols, clear,
						bool,onlyId,
						after, before, today, start, end 	// 日期
					} = v
					label = label ?? _label
					if( expose?.submit ) exposeRef.current = expose
					// 元素属性
					el = {
						label, name, size, form, formRef, mul, domRef, suffix, antd, p,
						disabled: $fn.isEmpty(v.disabled ) ? disabled : v.disabled,
						readOnly: $fn.isEmpty(v.readOnly ) ? readOnly : v.readOnly,
						format,
						onChanged: value => {
							if( change ){
								$fn.func(change,{ ...value, formRef, ref:exposeRef.current })
							}
							if( v.search ) formRef().submit()
						},
						...el
					}
					cache = $fn.isNotEmpty(v.cache) ? v.cache : cache
					const apiElement = { data, mode, setName, allowClear:clear, cache, param, submit, sname, api, nameStr, idStr, subtxt:v.subtxt, ...el  }
					
					// width
					let itemWidth = v.width ?? '100%'
					if(v.half){ itemWidth = '50%' }
					if( isSearch || x ){ itemWidth = labelWidth ? (v.width || width) :  'auto'	}
					itemWidth = $fn.strToNum(itemWidth)
					
					let elWidth = '100%'
					
					if(isSearch && !labelWidth){
						elWidth = 160
						if(['input-range'].includes( type )){
							elWidth = elWidth * 2
						}
						if(['text','password','textarea','number', 'input-range', 'tree-select', 'select','date', 'date-range'].includes( type ) || !type){
							const _width  = v.width || width
							if( _width ) elWidth = $fn.strToNum(_width)
						}
						
					}
					
					if( $fn.isNotEmpty( hide ) ){
						hide = $fn.getResult(hide)
						if(hide) return null
					}
					
					let Component = <Input width={elWidth} {...el} />
					
					let itemLabel = _label ? '' : label
					
					// type
					switch(type){
						case 'select':
							Component = <Select width={elWidth} count={v.count} listHeight={v.listHeight} group={v.group} {...apiElement} />
							break
						case 'tree-select':
							Component = <TreeSelect width={elWidth} {...apiElement} check={v.check} expand={v.expand} count={v.count} />
							break;
						case 'tree':
							Component = <Tree width={elWidth} {...apiElement} check={v.check} expand={v.expand} mode={mode} perm={v.perm} />
							break;
						case 'cascader':
							Component = <Cascader ref={cascaderRef} width={elWidth} onlyId={onlyId} level={v.level} { ...apiElement } />
							break;
						case 'checkbox-group':
							Component = <CheckboxGroup {...apiElement} />
							break;
						case 'checkbox':
							v.colon = false;
							itemLabel = ml ? '' : ' '
							Component = <Checkbox {...el} />
							break
						case 'switch':
							Component = <Switch {...el}  bool={bool}/>
							break
						case 'radio':
							Component = <Radio {...apiElement} bool={bool}/>
							break
						case 'input-range':
							Component = <InputRange width={elWidth} mode={mode} {...el} />
							break
						case 'upload':
							el = { mongo, mode, click, api, fileType:v.fileType, showList:v.showList, listType:v.listType, ...el}
							Component = <Upload {...el} />
							break
						case 'date':
							{
								let dateWidth = '100%'
								if(isSearch && !labelWidth){
									dateWidth = !format ? elWidth : 154
								}
								el = { after, before, today, start, end, width:dateWidth, ...el}
								Component = <DatePicker {...el} />
							}
							break
						case 'date-range':
							{
								let rangeWidth = '100%'
								if(isSearch){
									if(!labelWidth) {
										const w = $fn.strToNum(v.width || width)
										rangeWidth = w  ? w : (!format ? 200 : 305 )
									}
								}
								el = { after, before, today, start, end, type, width:rangeWidth, ...el}
								Component = <DatePicker {...el} />
							}
							break
						case 'date-range-split':
							{
								let rangeSplitWidth = '100%'
								if(isSearch){
									if(!labelWidth) {
										const w = $fn.strToNum(v.width || width)
										rangeSplitWidth = w  ? w : (!format ? 250 : 305 )
									}
								}
								el = { after, before, today, start, end, type, width:rangeSplitWidth, ...el}
								Component = <DatePickerRange {...el} />
							}
							break
						case 'time':
							{
								let dateWidth = '100%'
								if(isSearch && !labelWidth){
									dateWidth = !format ? elWidth : 154
								}
								el = { width:dateWidth, ...el}
								Component = <TimePicker {...el} />
							}
							break
						case 'transfer':
							el = { height, ...apiElement }
							Component = <Transfer {...el} />
							break
						case 'table':
							table = $fn.getResult(table, { data: infoData });
							Component = <Table isSubmitForm { ...table }/>
							break
						case 'select-content':
							el = { mode, click, ...el}
							Component = <SelectContent {...el} />
							break
						case 'table-edit':
							Component = <TableEdit {...el} status={v.status} cols={v.cols} group={v.group} p={v.p} summary={v.summary} />
							break
						default:
							if( v.slot ){
								Component = $fn.isFunction(v.slot) ? v.slot({...el, height, cols, api, value:listData?.[name], data:listData}) : v.slot
							}else{
								if( ctrlMode === 'list' ){
									Component = <Input width={elWidth} {...el} rows={v.rows} type={type} readOnly p='--' />
								}else{
									if( ['password','textarea','number'].includes( type )){
										let maxLength= null 
										if( v.maxLength || v.maxLength === null ){
											maxLength = v.maxLength
										}else{
											if( type==='textarea' ) maxLength = 30
										}
										Component = <Input width={elWidth} {...el} rows={v.rows} type={type} maxLength={maxLength} />
									}
								}
							}
					}
					
					if(x){
						mb = 0
						switch(type){
							case 'data-range':
								break
							default:
								break;
						}
					}
					//
					let message = '输入'
					
					if(!p){ 
						if(['select', 'tree-select', 'tree', 'transfer', 'select-content', 'date', 'date-range', 'date-range-split'].includes( type )){ message = '选择' }
						else if(type === 'upload'){ message = '上传' }
						message = p ? p : `请${message}${label}`
					}else{
						if( _label ){
							message = `请${message}${label}`
						}else{
							message = names ? `请${message}${label}` : p
						}
					}
					let _rules = Rules(v, message)
					
					// item 属性
					const item = {
						label: itemLabel,
						name,
						width:itemWidth,
						mt: v.mt,
						mb: v.mb ?? mb,
						ml: v.ml,
						mr: v.mr,
						colon: v.colon ?? colon,
						className: `jzer-item-${ type ?? 'text' } ${ v.class||'' }`,
						dependencies: _rules?.dependencies,
						rules: _rules?.rule,
					}
					let cpt = <FormItem {...item} >{ Component }</FormItem>
					const formItemWidth = (v.endSlot || v.unit) && (type==='radio' || type==='switch') ? 'auto' : '100%'
					if(v.endSlot){
						cpt = <div className={'fx lh30'} style={{width:itemWidth}}><FormItem {...item} width={ formItemWidth } >{ Component }</FormItem>{v.endSlot}</div> 
					}else if( v.unit ){
						cpt = <div className={'fx lh30'} style={{width:itemWidth}}><FormItem  {...item} width={ formItemWidth }>{ Component }</FormItem><div className='g6 ml5 f12 nowrap'>{v.unit}</div></div>
					}
					return (
						<Fragment key={i}>
							{ 
								!v.splitSlot && !v.title ? (
									<>
										{ !!v.br && <div className='w'></div> }
										{ cpt }
									</>
								) : (
									<>
										{ v.splitSlot && <div className='w'>{ v.splitSlot }</div> }
										{ v.title && ( $fn.isString(v.title) ? <Title title={v.title} className='mb10 w' /> : <Title className='mb10 w' {...v.title}/> ) }
									</>
								)
							}
							
						</Fragment>
					)
				})
			}
		</div>
	)
}
export default Index